using System;
using System.Collections;
using System.Data;
using System.Threading;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Agreements;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.InsightWebControls;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Security.Enumerations;
using PHSRAG.Utility;
using PHSRAG.WebControls;
using Constants=PHSRAG.Insight21.InsightUtilities.Constants;
using Helper=PHSRAG.WebControls.Helper;

namespace PHSRAG.Insight21
{
    /// <summary>
    /// The FinancialSummary page provides a single row of financial data for each fund
    /// accessible to the user.  The financial data includes the overall fund budget amount
    /// expenses to date, previous month expenses, revenues to date, budget balance, cash
    /// balance, projected PO/AP expenses, Projected Personnel expenses, Projected balance.
    /// In addition to html page output, this data can be downloaded to PDF and Excel formats.
    /// </summary>
    public partial class FinancialSummary : NoCachePage
    {
        #region Constants

        private const string ActiveFundStatus = "1";
        private const string ActiveFundStatusText = "Active Fund";
        private const string CostOptionKey = "CostOption_12B90EAE-E704-444a-8733-800F3F39866C";
        private const string CurrentPageIndexKey = "CurrentPageIndex_12B90EAE-E704-444a-8733-800F3F39866C";
        private const string ExcelReportControlFilePath = "../../Agreements/Reports/FinancialSummaryExcel.ascx";
        private const string FundNumberKey = "FundNumber_12B90EAE-E704-444a-8733-800F3F39866C";
        private const char LabelValueSeparator = '|';
        private const string SearchCriteriaVersionKey = "SearchCriteriaVersion_12B90EAE-E704-444a-8733-800F3F39866C";
        private const string SearchCriteriaVersionKeyAgr = "SearchCriteriaVersion_27447545-6976-4179-A0A7-B3AFED489466";
        private const string SortColumnKey = "SortColumn_12B90EAE-E704-444a-8733-800F3F39866C";
        private const string SortDirectionKey = "SortAscending_12B90EAE-E704-444a-8733-800F3F39866C";

        #endregion

        #region Private Types

        /// <summary>
        /// The ColumnIndex enumeration defines the sequence of columns in the data grid. This MUST be kept in sync with the
        /// declaration on the ASPX side.
        /// </summary>
        private enum ColumnIndex
        {
            AgreementType,
            FundNumber,
            PILastFirstName,
            TotalBudgetAmount,
            LastMoExpenses,
            ExpensesToDate,
            BudgetBalance,
            Revenue,
            CurrentCashBalance,
            POAPBalance,
            PlannedSalary,
            ProjectedBalance,
            ProjectStartDate,
            ProjectEndDate,
            BudgetStartDate,
            BudgetEndDate
        }

        /// <summary>
        /// Report types supported by the page.
        /// </summary>
        private enum ReportType
        {
            Excel,
            PDF
        }

        #endregion

        #region Instance Variables (Protected)

        private ExpansionToggler expansionToggler;

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private Properties

        /// <summary>
        /// Get the Agreements (summary of agreements) that the logged-in user has access to. The list of agreements is
        /// is maintained by the Agreements business object within its data container. The Agreements object is cached.
        /// </summary>
        private FinancialSummaries FinancialSummaries
        {
            get
            {
                FinancialSummaries financialSummaries =
                    ResultsCache.GetObject(cachePolicy, FinancialSummaries.CacheKey) as FinancialSummaries;

                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                int searchVersion = searchCriteria.Version;

                if (financialSummaries == null || ((searchContext != null) && (searchVersion != SearchCriteriaVersion)))
                {
                    // When this page loads, we want the active funds to come back, but the 
                    // search criteria isn't setup until AgreementSearch loads, so set that
                    // one property here.
                    if (searchVersion == 0)
                    {
                        DropDownList ddl = (DropDownList) (expandingPanel.FindControl("agreementSearch").FindControl(Constants.FundStatusIDKey));
                        searchCriteria.Add(ddl.ID, ActiveFundStatus);
                        if (ddl.Attributes["Label"] != null)
                        {
                            searchCriteria.ControlLabels.Add(ddl.ID,
                                String.Format("{0}{1}{2}", ddl.Attributes["Label"], LabelValueSeparator,
                                    ActiveFundStatusText));
                        }
                    }

                    SearchCriteriaVersion = searchVersion;

                    ResultsCache.PurgeObject(cachePolicy);

                    searchCriteria[Constants.PIIDKey] = searchCriteria["piName"];
                    financialSummaries = new FinancialSummaries();
                    financialSummaries.Load(DataAccess.GetConnectionString(), searchCriteria,
                        refreshDates.GLPostAsOfDate.ToShortDateString(), IncludeIndirectCosts, SortColumn, SortAscending, Session.SessionID);

                    ResultsCache.SetObject(cachePolicy, FinancialSummaries.CacheKey, financialSummaries);
                }

                return financialSummaries;
            }
        }

        /// <summary>
        /// Gets/sets an integer value indicating the search criteria version. 
        /// The version number changes when the search criteria changes.  This signals the page to re-build its
        /// cache.
        /// </summary>
        /// <remarks>
        /// This and all properties required to re-establish the page are stored as name / value pairs in
        /// a hash table stored in the page cache under the key Keys.FinancialSummaryPageKey.
        /// This enables the page to re-establish its state with minimal IO to what it was when
        /// the user last visited it.
        /// </remarks>
        private int SearchCriteriaVersion
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable;
                return (h == null || h[SearchCriteriaVersionKey] == null) ? 0 : (int) h[SearchCriteriaVersionKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable ?? new Hashtable();
                h[SearchCriteriaVersionKey] = value;
                pageCachePolicy.Cache(Keys.FinancialSummaryPageKey, h);
                Hashtable h1 = pageCachePolicy.GetCachedObject(Keys.AgreementSummaryPageKey) as Hashtable ?? new Hashtable();
                h1[SearchCriteriaVersionKeyAgr] = value;
                pageCachePolicy.Cache(Keys.AgreementSummaryPageKey, h1);
            }
        }

        /// <summary>
        /// Private boolean property used to get/set if the sort order is ascending or descending.
        /// </summary>
        /// <remarks>
        /// This and all properties required to re-establish the page are stored as name / value pairs in
        /// a hash table stored in the page cache under the key Keys.FinancialSummaryPageKey.
        /// This enables the page to re-establish its state with minimal IO to what it was when
        /// the user last visited it.
        /// </remarks>
        private bool SortAscending
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable;
                if (h == null)
                {
                    return true;
                }
                object sortAscending = h[SortDirectionKey];
                return (sortAscending == null) ? true : (bool) sortAscending;
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable ?? new Hashtable();
                h[SortDirectionKey] = value;
                pageCachePolicy.Cache(Keys.FinancialSummaryPageKey, h);
            }
        }

        /// <summary>
        /// Private boolean property used to get/set the base sorting column.
        /// </summary>
        /// <remarks>
        /// This and all properties required to re-establish the page are stored as name / value pairs in
        /// a hash table stored in the page cache under the key Keys.FinancialSummaryPageKey.
        /// This enables the page to re-establish its state with minimal IO to what it was when
        /// the user last visited it.
        /// </remarks>
        private string SortColumn
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable;
                if (h == null)
                {
                    return "CurrentCashBalance";
                }
                object sortColumn = h[SortColumnKey];
                return (sortColumn == null) ? "CurrentCashBalance" : (string) sortColumn;
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable ?? new Hashtable();
                h[SortColumnKey] = value;
                pageCachePolicy.Cache(Keys.FinancialSummaryPageKey, h);
            }
        }

        /// <summary>
        /// Gets/sets the cost option which when set to true means total cost and when set to false means direct cost.
        /// </summary>
        /// <remarks>
        /// This and all properties required to re-establish the page are stored as name / value pairs in
        /// a hash table stored in the page cache under the key Keys.FinancialSummaryPageKey.
        /// This enables the page to re-establish its state with minimal IO to what it was when
        /// the user last visited it.
        /// </remarks>
        private bool IncludeIndirectCosts
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable;
                return (h == null || h[CostOptionKey] == null) ? true : (bool) h[CostOptionKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable ?? new Hashtable();
                h[CostOptionKey] = value;
                pageCachePolicy.Cache(Keys.FinancialSummaryPageKey, h);
            }
        }

        /// <summary>
        /// Get/set the current page index.
        /// </summary>
        /// <remarks>
        /// PLEASE NOTE: that this property sets the dataGrid.CurrentPageIndex property.
        /// This and all properties required to re-establish the page are stored as name / value pairs in
        /// a hash table stored in the page cache under the key Keys.FinancialSummaryPageKey.
        /// This enables the page to re-establish its state with minimal IO to what it was when
        /// the user last visited it.
        /// </remarks>
        private int CurrentPageIndex
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable;
                return (h == null || h[CurrentPageIndexKey] == null) ? 0 : (int) h[CurrentPageIndexKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.FinancialSummaryPageKey) as Hashtable ?? new Hashtable();
                h[CurrentPageIndexKey] = value;
                dataGrid.CurrentPageIndex = value;
                pageCachePolicy.Cache(Keys.FinancialSummaryPageKey, h);
            }
        }

        /// <summary>
        /// Gets the boolean value, to decide whether or not to load the grid
        /// </summary>
        public bool IsOkayToLoadGrid
        {
            get
            {
                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                if (null == searchContext)
                {
                    return false;
                }

                SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;

                return !(userContext.ShouldPromptForResourceSearch(Constants.Modules.Agreements) && searchCriteria.Count < 3 && (searchCriteria.Version <= 0 || SearchCriteriaVersion == -1));
            }
        }

        /// <summary>
        /// Gets the boolean value, to decide whether or not to display Overview Pages
        /// </summary>
        public bool IsOkayToShowOverview
        {
            get
            {
                CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                if (null == searchContext)
                {
                    return false;
                }

                SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;

                if (!(userContext.ShouldPromptForResourceSearch(Constants.Modules.Agreements) && searchCriteria.Count < 3))
                {
                    FinancialSummaries financialSummaries =
                        ResultsCache.GetObject(cachePolicy, FinancialSummaries.CacheKey) as FinancialSummaries;

                    if (null != financialSummaries)
                    {
                        if (financialSummaries.Count > Settings.GetKeyValue(Keys.FinancialSummaryOverviewLimitKey, 0))
                        {
                            if (0 != (userContext.ModuleRoleBitmask & (int) ModuleRoleBit.NoAgreementOverviewLimit))
                            {
                                return true;
                            }
                        }
                        else
                        {
                            return true;
                        }
                    }
                }

                return false;
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>Re-establishes the page context in between postbacks.</summary>
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                annunciator.Message = string.Empty;
                annunciator.Title = string.Empty;
                breadCrumb.Add("Financial Summary", Settings.GetKeyValue("SubNavigation.Agreements.FinancialSummaryURL", ""), 1);

                refreshDates.GLAsOfDateVisible = true;
                refreshDates.POAPAsOfDateVisible = true;
                refreshDates.SalaryAsOfDateVisible = true;

                // If this is not a postback, establish the state of various page controls.
                if (!IsPostBack)
                {
                    ((ExpansionToggler) expandingPanel.FindControl("expansionToggler")).HelpText =
                        Constants.SearchHelpText;

                    header.ModuleName = Constants.Modules.Agreements;
                    costOption.SelectedIndex = Convert.ToInt32(IncludeIndirectCosts);

                    // Load the grid and either initialize the pager if first page, or just manage
                    // navigation links if not on the first page.  It might not be the first page if
                    // this page was visited, exited, and re-visited.

                    dataGrid.PageSize = Settings.GetKeyValue("DataGrid.ItemsPerPage", 5);

                    expansionToggler = (ExpansionToggler) expandingPanel.FindControl("expansionToggler");
                    if (IsOkayToLoadGrid)
                    {
                        downloadBar.Visible = true;
                        if (expansionToggler != null)
                        {
                            expansionToggler.ShowOverViewHeaderHint = false;
                        }

                        expandingPanel.IsExpanded = false;

                        LoadDataGrid();

                        agreementsSubNavigation.EnableOverviewNavigation = IsOkayToShowOverview;
                    }
                    else
                    {
                        if (expansionToggler != null)
                        {
                            expansionToggler.ShowOverViewHeaderHint = true;
                        }

                        ManagePagination();
                        expandingPanel.IsExpanded = true;
                        agreementsSubNavigation.EnableOverviewNavigation = false;
                        downloadBar.Visible = false;
                    }

                    // get rid of the details keys, item command event handler will recreate if needed.
                    pageCachePolicy.UnCache(Constants.AgreementsConstants.AgreementDetailsKey);

                    // Reset the sub-navigation control such that on entry into this module, any hysterisis at the sub-navigation
                    // level from sibling modules does not prevail.

                    agreementsSubNavigation.ResetOverviewNavigation();

                    if (dataGrid.Items.Count != 0)
                    {
                        dataGrid.Visible = true;
                    }
                }
                else
                {
                    if (dataGrid.Items.Count != 0)
                    {
                        dataGrid.Visible = true;
                    }
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during PageLoad:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
            finally
            {
                agreementsSubNavigation.SelectedLink = "Financial Summary";
            }
        }

        /// <summary>
        /// Sets the page index to zero, loads the grid and adjusts the active
        /// paging links according to the location in the array of financial summary Ids.
        /// </summary>
        protected void OnFirstPage(object sender, CommandEventArgs e)
        {
            CurrentPageIndex = 0;
            LoadDataGrid();
        }

        /// <summary>
        /// Indicates the sort column and the sort order.  It references the private properties for
        /// SortColumn and SortAscending and sets the appropriate web ding in the appropriate column
        /// of the grid header.
        /// </summary>
        protected void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Header && dataGrid.Visible)
                {
                    FinancialSummaries financialSummaries = FinancialSummaries;
                    Label sortSymbol = new Label();
                    sortSymbol.CssClass = "Sort";
                    sortSymbol.Text = SortAscending ? Constants.SortAscendingText : Constants.SortDescendingText;
                    sortSymbol.Font.Name = Constants.SortSymbolFontName;

                    string sortColumn = SortColumn;
                    foreach (DataGridColumn column in dataGrid.Columns)
                    {
                        if (column.SortExpression == sortColumn)
                        {
                            (e.Item.Cells[dataGrid.Columns.IndexOf(column)]).Controls.Add(sortSymbol);
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during DataGrid item creation:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Sets the page index to the last page, loads the grid and adjusts
        /// the pager controls navigation links.
        /// </summary>
        protected void OnLastPage(object sender, CommandEventArgs e)
        {
            try
            {
                CurrentPageIndex = pagerAboveDatagrid.PageCount - 1;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to last page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// If not on the last page, increments the page index, loads the grid and adjusts
        /// the pager controls navigation links.
        /// </summary>
        protected void OnNextPage(object sender, CommandEventArgs e)
        {
            try
            {
                ++CurrentPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to next page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// If the current page is greater than 0, decrements the current page index,
        /// loads the data grid and adjusts the pager controls navigation links.
        /// </summary>
        protected void OnPreviousPage(object sender, CommandEventArgs e)
        {
            try
            {
                --CurrentPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred navigating to previous page:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Processes sort criteria specified, loads the financial summaries into the dataGrd and
        /// initializes the page controls.
        /// </summary>
        /// <remarks>
        /// Toggles the sort direction, cleans the cache and loads the datagrid.
        /// </remarks>
        protected void OnSort(object source, DataGridSortCommandEventArgs e)
        {
            try
            {
                if (e.SortExpression != string.Empty)
                {
                    PurgeCache();
                    SortAscending = (SortColumn == e.SortExpression) ? !SortAscending : true;
                    SortColumn = e.SortExpression;
                    CurrentPageIndex = 0;
                    LoadDataGrid();
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during sort:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Gets the search criteia and performs a search.
        /// </summary>
        protected void OnSearch(SearchCriteriaArgs args)
        {
            try
            {
                if (SearchCriteriaVersion == -1)
                {
                    ++SearchCriteriaVersion;
                }

                CommonSearchContext searchContext = cachePolicy.GetCachedObject(CommonSearchContext.CacheKey) as CommonSearchContext;
                if (searchContext != null)
                {
                    SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
                    if (searchCriteria.Version != SearchCriteriaVersion)
                    {
                        PurgeCache();
                    }

                    // the RegularExpresssionValidator on the page should prevent non-numeric
                    // values from getting this far, but we'll check anyway just to be sure
                    Object o = searchCriteria[Constants.BalanceLessThanKey];
                    if (o != null)
                    {
                        try
                        {
                            Convert.ToDouble(o);
                        }
                        catch
                        {
                            annunciator.Message = "'Balance less than' must be a valid currency amount without commas";
                            return;
                        }
                    }

                    expansionToggler = (ExpansionToggler) expandingPanel.FindControl("expansionToggler");
                }

                CurrentPageIndex = 0;
                LoadDataGrid();

                if (IsOkayToShowOverview)
                {
                    if (expansionToggler != null)
                    {
                        agreementsSubNavigation.EnableOverviewNavigation = true;
                    }
                    expansionToggler.ShowOverViewHeaderHint = false;
                }
                else
                {
                    if (expansionToggler != null)
                    {
                        expansionToggler.ShowOverViewHeaderHint = true;
                    }
                    agreementsSubNavigation.EnableOverviewNavigation = false;
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during search:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Invoked by the download bar when it catches an exception.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnDownloadFailed(object sender, CommandEventArgs e)
        {
            annunciator.Title = "Following error(s) occurred while downloading";
            annunciator.Message = ExceptionReport.GetExceptionInfo((Exception) e.CommandArgument, false);
        }

        /// <summary>
        /// Formats the currency columns of the dataGrid. Formatting only happens to Item types and
        /// Alternating Item types.  As a security measure, the link button on the planned salaries
        /// column is substituted by a literal control if the user does not have access to
        /// view salary information.  Also, the footer is loaded here from the private properties
        /// containing the totals for the data grid.
        /// </summary>
        protected void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                //Format the currency columns on the datagrid for items and alternating items.
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    DataSet fundInfo = FinancialSummaries.GetFundInfo(CurrentPageIndex*dataGrid.PageSize, dataGrid.PageSize);
                    DataRow sourceDataRow = fundInfo.Tables[0].Select(string.Format("FundID={0}", dataGrid.DataKeys[e.Item.ItemIndex]))[0];
                    ((LinkButton) e.Item.Cells[(int) ColumnIndex.FundNumber].Controls[0]).ToolTip = (string) sourceDataRow["ToolTip"];

                    FormatCurrencyInLabel(e, ColumnIndex.TotalBudgetAmount);
                    FormatCurrencyInLinkButton(e, ColumnIndex.LastMoExpenses);
                    FormatCurrencyInLinkButton(e, ColumnIndex.ExpensesToDate);
                    FormatCurrencyInLinkButton(e, ColumnIndex.BudgetBalance);
                    FormatCurrencyInLinkButton(e, ColumnIndex.Revenue);
                    FormatCurrencyInLabel(e, ColumnIndex.CurrentCashBalance);
                    FormatCurrencyInLinkButton(e, ColumnIndex.POAPBalance);
                    FormatCurrencyInLinkButton(e, ColumnIndex.PlannedSalary);
                    FormatCurrencyInLinkButton(e, ColumnIndex.ProjectedBalance);


                    if (sourceDataRow["BudgetStartDate"] == DBNull.Value)
                    {
                        e.Item.Cells[(int) ColumnIndex.BudgetStartDate].Text = null;
                    }

                    // Make the link button a Literal control if the user does not have access to see salaries for
                    // a particular fund.
                    if ((Convert.ToInt32(sourceDataRow["AccessLevel"]) & (int) AccessRightBit.ViewSalaryInformation) == 0)
                    {
                        TableCell plannedSalary = e.Item.Cells[(int) ColumnIndex.PlannedSalary];
                        string dataValue = ((LinkButton) plannedSalary.Controls[0]).Text;
                        plannedSalary.Controls.Clear();
                        plannedSalary.Controls.Add(new LiteralControl(dataValue));
                    }

                    foreach (TableCell cell in e.Item.Cells)
                    {
                        if (cell.Controls.Count == 0)
                        {
                            cell.EnableViewState = false;
                        }
                    }
                }

                    // Load the screen totals bar.
                else if (e.Item.ItemType == ListItemType.Footer)
                {
                    e.Item.Cells[(int) ColumnIndex.AgreementType].Text = "Totals";
                    FormatCurrencyInFooter(e, ColumnIndex.TotalBudgetAmount, FinancialSummaries.TotalBudgetAmount);
                    FormatCurrencyInFooter(e, ColumnIndex.LastMoExpenses, FinancialSummaries.TotalLastMoExpenses);
                    FormatCurrencyInFooter(e, ColumnIndex.ExpensesToDate, FinancialSummaries.TotalExpensesToDate);
                    FormatCurrencyInFooter(e, ColumnIndex.BudgetBalance, FinancialSummaries.TotalBudgetBalance);
                    FormatCurrencyInFooter(e, ColumnIndex.Revenue, FinancialSummaries.TotalRevenue);
                    FormatCurrencyInFooter(e, ColumnIndex.CurrentCashBalance, FinancialSummaries.TotalCurrentCashBalance);
                    FormatCurrencyInFooter(e, ColumnIndex.POAPBalance, FinancialSummaries.TotalOpenPOAPBalance);
                    FormatCurrencyInFooter(e, ColumnIndex.PlannedSalary, FinancialSummaries.TotalPlannedSalary);
                    FormatCurrencyInFooter(e, ColumnIndex.ProjectedBalance, FinancialSummaries.TotalProjectedBalance);

                    foreach (TableCell cell in e.Item.Cells)
                    {
                        cell.EnableViewState = false;
                    }
                }
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred during datagrid item binding:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Handles linking to other pages when a link is clicked on the data Grid.  If a control was clicked
        /// on the grid on an item or alternating item row, redirect to the new page that is specified in the
        /// CommandName property.  The data associated with the click event will be passed in the session
        /// cache as a hash table keyed by Keys.AgreementDetailsKey.  Inside the hash table are name value pairs
        /// containing the data.
        /// </summary>
        protected void OnDataGridItemCommand(object source, DataGridCommandEventArgs e)
        {
            try
            {
                //Whenever a link is clicked, load up the name value pairs to pass to the next page and redirect
                //to it.

                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    DataSet fundInfo = FinancialSummaries.GetFundInfo(CurrentPageIndex*dataGrid.PageSize, dataGrid.PageSize);
                    DataRow sourceDataRow = fundInfo.Tables[0].Select(string.Format("FundID={0}", dataGrid.DataKeys[e.Item.ItemIndex]))[0];

                    Hashtable dictionary = new Hashtable();
                    dictionary.Add(Keys.AgreementIdKey, Convert.ToInt32(sourceDataRow["AgreementId"]));
                    dictionary.Add(Keys.FundNumberKey, ((LinkButton) e.Item.Cells[(int) ColumnIndex.FundNumber].Controls[0]).Text);

                    string glPostAsOfDate = refreshDates.GLPostAsOfDate.ToShortDateString();
                    string[] commands = e.CommandName.Split(',');
                    if (commands.Length > 1 && commands[1] == "LastMoExpenses")
                    {
                        dictionary.Add(Keys.JournalStartDateKey, MonthBeginingDate(glPostAsOfDate));
                    }
                    else if (commands.Length > 1 && commands[1] == "ExpensesToDate")
                    {
                        dictionary.Add(Keys.AllExpensesKey, "true");
                        dictionary.Add(Keys.JournalStartDateKey, "1/1/1900");
                        // revenue breakdown page now uses RevenueStartDateKey instead of JournalStartDateKey
                        dictionary.Add(Keys.RevenueStartDateKey, "1/1/1900");
                    }
                    else
                    {
                        dictionary.Add(Keys.JournalStartDateKey, "1/1/1900");
                        // revenue breakdown page now uses RevenueStartDateKey instead of JournalStartDateKey
                        dictionary.Add(Keys.RevenueStartDateKey, "1/1/1900");
                    }

                    dictionary.Add(Keys.JournalEndDateKey, glPostAsOfDate);
                    // revenue breakdown page now uses RevenueEndDateKey instead of JournalEndDateKey
                    dictionary.Add(Keys.RevenueEndDateKey, glPostAsOfDate);
                    dictionary.Add(Keys.RevenueTotalKey, ((LinkButton) e.Item.Cells[(int) ColumnIndex.Revenue].Controls[0]).Text);
                    dictionary.Add(Keys.SalaryAsOfDateKey, refreshDates.SalaryAsOfDate.ToShortDateString());

                    dictionary.Add(Constants.AgreementsConstants.AccessRightsKey, Convert.ToInt32(sourceDataRow["AccessLevel"]));
                    //if we selected Open POAPs we go to TransactionDetails so we'll cache this in the selected
                    //link key.  Transaction Details will know to load up encumbrances and will blow the cache away.
                    if (e.CommandName == "TransactionDetails.aspx")
                    {
                        pageCachePolicy.Cache(Keys.SelectedLinkKey, "TransactionDetails.aspx");
                    }

                    string budgetStartDate = e.Item.Cells[(int) ColumnIndex.BudgetStartDate].Text;
                    dictionary.Add(Keys.BudgetYearKey, (budgetStartDate == string.Empty) ? 0 : Convert.ToDateTime(budgetStartDate).Year);
                    dictionary.Add(Keys.RefreshBudgetDetailDataKey, true);

                    pageCachePolicy.Cache(Constants.AgreementsConstants.AgreementDetailsKey, dictionary);
                    PurgeCache();

                    CommonSearchContext searchContext = (CommonSearchContext) cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
                    searchContext.CurrentLevel = SearchCriteria.Level.Detail;
                    Page.Response.Redirect(commands[0], false);
                }
            }
            catch (ThreadAbortException)
            {
                // We get here due to the Redirect. This is benign.
            }
            catch (Exception ex)
            {
                annunciator.Title = string.Format("Following error(s) occurred while attempting to transfer to page {0} FundNumber={1}:",
                    e.CommandName, ((LinkButton) e.Item.Cells[(int) ColumnIndex.FundNumber].Controls[0]).Text);
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Handler for the event raised by the CommonSearch control when the "Clear Selection" buttion is clicked upon.
        /// The control clears the criretria (specific to this module).
        /// Since in the page life-cycle, the Load occurs before the Clear event, we have to instigate a re-load of the
        /// data grid to refelect the fact that the search criteria has been cleared.
        /// </summary>
        /// <param name="sender">Sender of the event</param>
        /// <param name="e">Argument associated with the event</param>
        protected void OnClearSelection(object sender, CommandEventArgs e)
        {
            SearchCriteriaVersion = -1;

            annunciator.Message = @"Verify the search criteria and click the 'Search' button to return the matching records.";
            dataGrid.DataSource = null;
            dataGrid.DataBind();
            downloadBar.Visible = false;
            ManagePagination();
            expandingPanel.IsExpanded = true;
            agreementsSubNavigation.EnableOverviewNavigation = false;
            expansionToggler = (ExpansionToggler) expandingPanel.FindControl("expansionToggler");
            if (expansionToggler != null)
            {
                if (!IsOkayToLoadGrid)
                {
                    expansionToggler.ShowOverViewHeaderHint = true;
                }
            }
        }

        /// <summary>
        /// Changes the cost option between All Costs and Exclude Indirect Costs.
        /// It then re-loads the new cost values into the grid.
        /// </summary>
        protected void OnCostOptionChange(object sender, EventArgs e)
        {
            try
            {
                IncludeIndirectCosts = Convert.ToBoolean(costOption.SelectedValue);
                PurgeCache();
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                annunciator.Title = "Following error(s) occurred changing cost option:";
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Resets the Agreements subnavigation selected link before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
            agreementsSubNavigation.Reset();
        }

        /// <summary>
        /// Purge the cache before navigating to an another page via the sub-navigation links.
        /// </summary>
        /// <param name="sender">The sub-navigation control</param>
        /// <param name="e">Contains event information</param>
        protected void OnSubNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        /// <summary>
        /// Purge the cache before navigating to the target page via breadcrumb links.
        /// </summary>
        /// <param name="sender">The BreadCrumb control</param>
        /// <param name="e">Contains event information</param>
        protected void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            PurgeCache();
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Calls GetFundIDs to get the dataset of fund IDs and then initializes the grid 
        /// and pager controls for the number of funds in the dataset.  It then gets an ArrayList of
        /// FinancialSummary objects that represent the current page to display in the dataGrid.  It
        /// binds this ArrayList to the dataGrid.
        /// </summary>
        private void LoadDataGrid()
        {
            try
            {
                FinancialSummaries financialSummaries = FinancialSummaries;
                dataGrid.VirtualItemCount = pagerBelowDatagrid.RecordCount = pagerAboveDatagrid.RecordCount = financialSummaries.Count;

                int currentPageIndex = CurrentPageIndex;
                int pageCount = (pagerAboveDatagrid.RecordCount/dataGrid.PageSize) +
                    (((pagerAboveDatagrid.RecordCount%dataGrid.PageSize) == 0) ? 0 : 1);
                pagerBelowDatagrid.PageCount = pagerAboveDatagrid.PageCount = pageCount;
                pagerBelowDatagrid.CurrentPage = pagerAboveDatagrid.CurrentPage = currentPageIndex + 1;

                dataGrid.DataSource = financialSummaries.GetFundInfo(currentPageIndex*dataGrid.PageSize, dataGrid.PageSize);
                dataGrid.DataBind();

                ManagePagination();

                if (dataGrid.Items.Count <= 0 && SearchCriteriaVersion != -1)
                {
                    downloadBar.Visible = false;
                    dataGrid.Visible = false;
                    annunciator.Message = "No funds found matching the search criteria.";
                }
                else
                {
                    downloadBar.Visible = true;
                    dataGrid.Visible = true;
                }
            }
            catch
            {
                dataGrid.Visible = pagerAboveDatagrid.Visible = pagerBelowDatagrid.Visible = false;
                throw;
            }
        }

        private void ManagePagination()
        {
            //please do not put dataGrid.visible as a check in the condition below.
            if (pagerBelowDatagrid.Visible = pagerAboveDatagrid.Visible = (dataGrid.Items.Count > 0 && SearchCriteriaVersion != -1))
            {
                int currentPageIndex = CurrentPageIndex;
                dataGrid.CurrentPageIndex = currentPageIndex;

                int startIndex = currentPageIndex*dataGrid.PageSize;

                pagerBelowDatagrid.FirstRecord = pagerAboveDatagrid.FirstRecord = startIndex + 1;
                pagerBelowDatagrid.LastRecord = pagerAboveDatagrid.LastRecord =
                    Math.Min(startIndex + dataGrid.PageSize, dataGrid.VirtualItemCount);

                pagerBelowDatagrid.EnableFirstPage = pagerAboveDatagrid.EnableFirstPage =
                    pagerBelowDatagrid.EnablePreviousPage = pagerAboveDatagrid.EnablePreviousPage =
                        (CurrentPageIndex != 0);

                pagerBelowDatagrid.EnableLastPage = pagerAboveDatagrid.EnableLastPage =
                    pagerBelowDatagrid.EnableNextPage = pagerAboveDatagrid.EnableNextPage =
                        (CurrentPageIndex != (pagerAboveDatagrid.PageCount - 1));
            }
        }

        /// <summary>
        /// Returns the first day of the month for a given date string.
        /// </summary>
        /// <param name="date">Date of which the first day of the month is desired.</param>
        /// <returns>The first day of the month as a date string.</returns>
        private string MonthBeginingDate(string date)
        {
            if (date == string.Empty)
            {
                return date;
            }
            DateTime monthBeginingDate = Convert.ToDateTime(date);
            return monthBeginingDate.AddDays(-monthBeginingDate.Day + 1).ToShortDateString();
        }

        private void FormatCurrencyInLabel(DataGridItemEventArgs e, ColumnIndex index)
        {
            TableCell cell = e.Item.Cells[(int) index];
            decimal amount = Convert.ToDecimal(cell.Text); // Math.Round(Convert.ToDecimal(cell.Text), 1);
            if (amount < 0)
            {
                cell.CssClass = "DataGridNegativeCurrencyItem";
            }
            cell.Text = Helper.ProcessDecimals(amount); //.ZeroDecimals());
        }

        private void FormatCurrencyInLinkButton(DataGridItemEventArgs e, ColumnIndex index)
        {
            TableCell cell = e.Item.Cells[(int) index];
            LinkButton button = (LinkButton) cell.Controls[0];
            decimal amount = Convert.ToDecimal(button.Text); // Math.Round(Convert.ToDecimal(button.Text), 1);
            if (amount < 0)
            {
                cell.CssClass = "DataGridNegativeCurrencyItem";
            }
            button.Text = Helper.ProcessDecimals(amount); //.ZeroDecimals());
            button.Enabled = (button.Text != Constants.ZeroDollarsNoCents);
        }

        private void FormatCurrencyInFooter(DataGridItemEventArgs e, ColumnIndex index, decimal amount)
        {
            TableCell cell = e.Item.Cells[(int) index];
            //amount = Math.Round(amount, 1);
            if (amount < 0)
            {
                cell.CssClass = "DataGridFooterRed";
            }
            cell.Text = Helper.ProcessDecimals(amount); //.ZeroDecimals());
        }

        /// <summary>
        /// Purge the cached BO from the cache and remove its key from the cache.
        /// </summary>
        private void PurgeCache()
        {
            System.Diagnostics.Trace.WriteLine("Purging FinancialSummaries...");
            ResultsCache.PurgeObject(cachePolicy);
        }

        #endregion

        #region Web Form Designer Generated Code

        /// <summary>
        /// Handler for the event raised when the page is being initialized.
        /// Retrieve the cache policy in force. Deposit event handlers to support the datagrid pagination.
        /// </summary>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //

            /*at098 - 01/17/2008
			 * The events have been wired in the aspx page             
			 */
            //InitializeComponent();
            base.OnInit(e);

            cachePolicy = (ICachePolicy) Session[Names.CachePolicyKey];
            pageCachePolicy = (ICachePolicy) Session[Names.CachePolicyKey];

            CommonSearch commonSearch = (CommonSearch) expandingPanel.FindControl("commonSearch");
            commonSearch.Field2AutoCompleteServicePath = Settings.GetKeyValue("CommonLookupWebservice", "");
        }

        #endregion
    }
}

// --- EOF ---